home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 5 / MacMania 5.toast / / Internet software / NewsWatcher / NW Source / Source / sfutil.c < prev    next >
Text File  |  1997-01-09  |  17KB  |  529 lines

  1. /*----------------------------------------------------------------------------
  2.  
  3.     sfutil.c
  4.  
  5.     This module contains Standard File utility routines.
  6.     
  7.     Copyright © 1994-1997, Northwestern University.
  8.  
  9. ----------------------------------------------------------------------------*/
  10.  
  11. #include <stdio.h>
  12.  
  13. #include "glob.h"
  14. #include "sfutil.h"
  15. #include "dialog.h"
  16. #include "menus.h"
  17. #include "newswatcher.h"
  18. #include "strutil.h"
  19. #include "fileutil.h"
  20.  
  21.  
  22.  
  23. #define kDirSelectDlg            200        /* Directory selection standard file dialog */
  24. #define kSelectDirButtonTop     11
  25. #define kSelectDirButtonBottom    10
  26.  
  27. #define kSaveArtDlg                                201        /* Save article standard file dialog */
  28. #define kSaveEncodedCheckbox                    13
  29. #define kSaveThreadsToSeparateFilesCheckbox        14
  30.  
  31. #define kAppendArtDlg                            202        /* Append article standard file dialog */
  32. #define kAppendEncodedCheckbox                    10
  33.  
  34.  
  35.  
  36. static StandardFileReply *gReply;                /* pointer to standard file reply record */
  37. static Boolean *gSaveEncodedText;                /* pointer to save encoded text option */
  38. static Boolean *gSaveThreadsToSeparateFiles;    /* pointer to save threads to separate
  39.                                                    files option */
  40. static AliasHandle gAlias;                        /* handle to alias to default directory, 
  41.                                                    or nil if none */
  42.  
  43. static FSSpec gDirTop;            /* file selected in top button */
  44. static FSSpec gDirBottom;        /* file selected in bottom button */
  45. static short gSelect;            /* 0 = cancel, 1 = top select button, 2 = bottom select button */
  46. static Str255 gPrevNameTop;        /* previous name in top button */
  47. static Str255 gPrevNameBottom;    /* previous name in bottom button */
  48.  
  49. static DlgHookYDUPP gGetPutHookUPP = nil;
  50. static DlgHookYDUPP gMyStandardAppendArticleHookUPP = nil;
  51. static DlgHookYDUPP gMyStandardPutArticleHookUPP = nil;
  52. static ModalFilterYDUPP gSFDialogFilterUPP = nil;
  53. static FileFilterYDUPP gGetDirectoryFilterUPP = nil;
  54. static DlgHookYDUPP gGetDirectoryHookUPP = nil;
  55.  
  56.  
  57.  
  58. /*----------------------------------------------------------------------------
  59.     SetStandardFileDirectoryFromAlias
  60.     
  61.     Initialize the standard file directory from a saved folder alias.
  62.     
  63.     Entry:    gReply = pointer to standard file reply record, or nil if none.
  64.             gAlias = handle to alias.
  65.             
  66.     Exit:    function result = item number which should be returned to
  67.                 standard file. 
  68. ----------------------------------------------------------------------------*/
  69.  
  70. static short SetStandardFileDirectoryFromAlias (void)
  71. {
  72.     short vRefNum, desktopVRefNum;
  73.     long dirID, desktopDirID;
  74.     Boolean valid;
  75.     OSErr err = noErr;
  76.     
  77.     if (gAlias == nil) return sfHookFirstCall;
  78.     ValidateSavedFolderAlias(gAlias, &vRefNum, &dirID, &valid);
  79.     if (!valid) return sfHookFirstCall;
  80.     err = FindFolder(vRefNum, kDesktopFolderType, false, 
  81.         &desktopVRefNum, &desktopDirID);
  82.     if (err == noErr && vRefNum == desktopVRefNum && dirID == desktopDirID) {
  83.         return sfHookGoToDesktop;
  84.     } else {
  85.         gReply->sfFile.vRefNum = vRefNum;
  86.         gReply->sfFile.parID = dirID;
  87.         *gReply->sfFile.name = 0;
  88.         return sfHookChangeSelection;
  89.     }
  90. }
  91.  
  92.  
  93.  
  94. /*----------------------------------------------------------------------------
  95.     SFDialogFilter 
  96.     
  97.     Event filter for standard file dialogs.
  98. ----------------------------------------------------------------------------*/
  99.  
  100. static pascal Boolean SFDialogFilter (DialogPtr dlg, EventRecord *ev, 
  101.     short *itemHit, void *yourDataPtr)
  102. {
  103.     Boolean result = false;
  104.     OSErr err = noErr;
  105.     ModalFilterUPP standardFilterProcUPP;
  106.  
  107.     if (ev->what == updateEvt && (WindowPtr)ev->message != dlg) {
  108.         HandleEvent(ev);
  109.         return false;
  110.     }
  111.     err = GetStdFilterProc(&standardFilterProcUPP);
  112.     if (err == noErr) {
  113.         result = CallModalFilterProc(standardFilterProcUPP, dlg, ev, itemHit);
  114.     }
  115.     return result;
  116. }
  117.  
  118.  
  119.  
  120. /*----------------------------------------------------------------------------
  121.     GetPutHook
  122.     
  123.     Dialog hook function for MyStandardGetFile and MyStandardPutFile.
  124. ----------------------------------------------------------------------------*/
  125.  
  126. static pascal short GetPutHook (short item, DialogPtr dlg, void *myDataPtr)
  127. {
  128.     if (GetWRefCon(dlg) != sfMainDialogRefCon) return item;
  129.     if (item == sfHookFirstCall) {
  130.         return SetStandardFileDirectoryFromAlias();
  131.     } else {
  132.         return item;
  133.     }
  134. }
  135.  
  136.  
  137.  
  138. /*----------------------------------------------------------------------------
  139.     MyStandardGetFile 
  140.     
  141.     Present the StandardGetFile dialog.
  142.     
  143.     The parameters are the same as in StandardGetFile, plus:
  144.     
  145.     Entry:    alias = handle to alias to default directory, or nil if none.
  146. ----------------------------------------------------------------------------*/
  147.  
  148. void MyStandardGetFile (FileFilterYDUPP fileFilter, short numTypes,
  149.     char *typeListString, StandardFileReply *reply, AliasHandle alias)
  150. {
  151.     Point where = {-1, -1};
  152.     SFTypeList typeList;
  153.     
  154.     PrepUserInteraction();
  155.     SetMenusTo(kAppleAllEnabled, 0, 0, 0, 0, 0);
  156.     gReply = reply;
  157.     gAlias = alias;
  158.     BlockMoveData(typeListString, typeList, 4*numTypes);
  159.     CustomGetFile(fileFilter, numTypes, typeList, reply, 0, where, gGetPutHookUPP,
  160.         gSFDialogFilterUPP, nil, nil, nil);
  161. }
  162.  
  163.  
  164.  
  165. /*----------------------------------------------------------------------------
  166.     MyStandardPutFile 
  167.     
  168.     Present the StandardPutFile dialog.
  169.     
  170.     The parameters are the same as in StandardPutFile, plus:
  171.     
  172.     Entry:    alias = handle to alias to default directory, or nil if none.
  173. ----------------------------------------------------------------------------*/
  174.  
  175. void MyStandardPutFile (ConstStr255Param prompt, ConstStr255Param defaultName,
  176.     StandardFileReply *reply, AliasHandle alias)
  177. {
  178.     Point where = {-1, -1};
  179.     
  180.     PrepUserInteraction();
  181.     SetMenusTo(kAppleAllEnabled, 0, 0, 0, 0, 0);
  182.     gReply = reply;
  183.     gAlias = alias;
  184.     CustomPutFile(prompt, defaultName, reply, 0, where, gGetPutHookUPP,
  185.         gSFDialogFilterUPP, nil, nil, nil);
  186. }
  187.  
  188.  
  189.  
  190. /*----------------------------------------------------------------------------
  191.     MyStandardAppendArticleHook
  192.     
  193.     Dialog hook function for MyStandardAppendArticle.
  194. ----------------------------------------------------------------------------*/
  195.  
  196. static pascal short MyStandardAppendArticleHook (short item, DialogPtr dlg, 
  197.     void *myDataPtr)
  198. {
  199.     if (GetWRefCon(dlg) != sfMainDialogRefCon) return item;
  200.     if (item == kAppendEncodedCheckbox) {
  201.         *gSaveEncodedText = !(*gSaveEncodedText);
  202.         DlgSetCheck(dlg, item, *gSaveEncodedText);
  203.         return sfHookNullEvent;
  204.     } else if (item == sfHookFirstCall) {
  205.         DlgSetCheck(dlg, kAppendEncodedCheckbox, *gSaveEncodedText);
  206.         return SetStandardFileDirectoryFromAlias();
  207.     } else {
  208.         return item;
  209.     }
  210. }
  211.  
  212.  
  213.  
  214. /*----------------------------------------------------------------------------
  215.     MyStandardAppendArticle 
  216.     
  217.     Present the append article dialog, with an extra checkbox to save
  218.     encoded text.
  219.     
  220.     The parameters are the same as in StandardGetFile, plus:
  221.     
  222.     Entry:    *saveEncodedText = default value for save encoded text option.
  223.             alias = handle to alias to default directory, or nil if none.
  224.     
  225.     Exit:    *saveEncodedText = true to save encoded text.
  226. ----------------------------------------------------------------------------*/
  227.  
  228. void MyStandardAppendArticle (FileFilterYDUPP fileFilter, short numTypes,
  229.     char *typeListString, StandardFileReply *reply, Boolean *saveEncodedText,
  230.     AliasHandle alias)
  231. {
  232.     Point where = {-1, -1};
  233.     SFTypeList typeList;
  234.     
  235.     PrepUserInteraction();
  236.     SetMenusTo(kAppleAllEnabled, 0, 0, 0, 0, 0);
  237.     gReply = reply;
  238.     gSaveEncodedText = saveEncodedText;
  239.     gAlias = alias;
  240.     BlockMoveData(typeListString, typeList, 4*numTypes);
  241.     CustomGetFile(fileFilter, numTypes, typeList, reply, kAppendArtDlg, where, 
  242.         gMyStandardAppendArticleHookUPP,
  243.         gSFDialogFilterUPP, nil, nil, nil);
  244. }
  245.  
  246.  
  247.  
  248. /*----------------------------------------------------------------------------
  249.     MyStandardPutArticleHook
  250.     
  251.     Dialog hook function for MyStandardPutArticle.
  252. ----------------------------------------------------------------------------*/
  253.  
  254. static pascal short MyStandardPutArticleHook (short item, DialogPtr dlg, 
  255.     void *myDataPtr)
  256. {
  257.     if (GetWRefCon(dlg) != sfMainDialogRefCon) return item;
  258.     if (item == kSaveEncodedCheckbox) {
  259.         *gSaveEncodedText = !(*gSaveEncodedText);
  260.         DlgSetCheck(dlg, item, *gSaveEncodedText);
  261.         return sfHookNullEvent;
  262.     } else if (item == kSaveThreadsToSeparateFilesCheckbox) {
  263.         *gSaveThreadsToSeparateFiles = !(*gSaveThreadsToSeparateFiles);
  264.         DlgSetCheck(dlg, item, *gSaveThreadsToSeparateFiles);
  265.         return sfHookNullEvent;
  266.     } else if (item == sfHookFirstCall) {
  267.         DlgSetCheck(dlg, kSaveEncodedCheckbox, *gSaveEncodedText);
  268.         DlgSetCheck(dlg, kSaveThreadsToSeparateFilesCheckbox, 
  269.             *gSaveThreadsToSeparateFiles);
  270.         return SetStandardFileDirectoryFromAlias();
  271.     } else {
  272.         return item;
  273.     }
  274. }
  275.  
  276.  
  277.  
  278. /*----------------------------------------------------------------------------
  279.     MyStandardPutArticle 
  280.     
  281.     Present the save article dialog, with an extra check box to save
  282.     encoded text.
  283.     
  284.     The parameters are the same as in StandardPutFile, plus:
  285.     
  286.     Entry:    *saveEncodedText = default value for save encoded text option.
  287.             *saveThreadsToSeparateFiles = default value for save threads to
  288.                 separate files options.
  289.             alias = handle to alias to default directory, or nil if none.
  290.     
  291.     Exit:    *saveEncodedText = true to save encoded text.
  292.             *saveThreadsToSeparateFiles = true to save threads to 
  293.                 separate files.
  294. ----------------------------------------------------------------------------*/
  295.  
  296. void MyStandardPutArticle (ConstStr255Param prompt, ConstStr255Param defaultName,
  297.     StandardFileReply *reply, Boolean *saveEncodedText, 
  298.     Boolean *saveThreadsToSeparateFiles, AliasHandle alias)
  299. {
  300.     Point where = {-1, -1};
  301.     
  302.     PrepUserInteraction();
  303.     SetMenusTo(kAppleAllEnabled, 0, 0, 0, 0, 0);
  304.     gReply = reply;
  305.     gSaveEncodedText = saveEncodedText;
  306.     gSaveThreadsToSeparateFiles = saveThreadsToSeparateFiles;
  307.     gAlias = alias;
  308.     CustomPutFile(prompt, defaultName, reply, kSaveArtDlg, where, 
  309.         gMyStandardPutArticleHookUPP,
  310.         gSFDialogFilterUPP, nil, nil, nil);
  311. }
  312.  
  313.  
  314.  
  315. /*----------------------------------------------------------------------------
  316.     GetDirectoryFilter 
  317.     
  318.     Filter function for MyGetStandardDirectory.
  319. ----------------------------------------------------------------------------*/
  320.  
  321. static pascal Boolean GetDirectoryFilter (ParmBlkPtr pb, void *myDataPtr)
  322. {
  323.     return (pb->fileParam.ioFlAttrib & 0x10) == 0 ||
  324.         (pb->fileParam.ioFlFndrInfo.fdFlags & fInvisible) != 0;
  325. }
  326.  
  327.  
  328.  
  329. /*----------------------------------------------------------------------------
  330.     EnableBottomButton 
  331.     
  332.     Enable or disable the bottom directory selection button.
  333.     
  334.     Entry:    dlg = pointer to dialog.
  335.             enabled = true to enable button, false to disable it.
  336. ----------------------------------------------------------------------------*/
  337.  
  338. static void EnableBottomButton (DialogPtr dlg, Boolean enabled)
  339. {
  340.     Handle itemHandle;
  341.     short itemType;
  342.     Rect box;
  343.     Boolean    oldEnable;
  344.  
  345.     GetDialogItem(dlg, kSelectDirButtonBottom, &itemType, &itemHandle, &box);
  346.     oldEnable = (itemType & itemDisable) == 0;
  347.     itemType = enabled ? itemType & (~itemDisable) : itemType | itemDisable;
  348.     SetDialogItem(dlg, kSelectDirButtonBottom, itemType, itemHandle, &box);
  349.     
  350.     if ((itemType & ctrlItem) != 0 && oldEnable != enabled) {
  351.         HiliteControl((ControlHandle)itemHandle, enabled ? 0 : 255);
  352.     }
  353. }
  354.  
  355.  
  356.  
  357. /*----------------------------------------------------------------------------
  358.     GetDirectoryHook
  359.     
  360.     Dialog hook function for MyGetStandardDirectory.
  361. ----------------------------------------------------------------------------*/
  362.  
  363. static pascal short GetDirectoryHook (short item, DialogPtr dlg, void *myDataPtr)
  364. {
  365.     Handle itemHandleTop, itemHandleBottom;
  366.     short itemType;
  367.     Rect boxTop, boxBottom;
  368.     CInfoPBRec pb;
  369.     short width;
  370.     CStr255 buttonTitle;
  371.     Str255 name;
  372.     short foundVRefNum;
  373.     long foundDirID;
  374.     Str255 select;
  375.     CStr255 fmt;
  376.     
  377.     if (GetWRefCon(dlg) != sfMainDialogRefCon) return item;
  378.  
  379.     GetPString(kStrFolderSelectNothing, select);
  380.     GetCString(kStrFolderSelectFmt, fmt);
  381.  
  382.     if (GetWRefCon(dlg) != sfMainDialogRefCon) return item;
  383.     GetDialogItem(dlg, kSelectDirButtonTop, &itemType, &itemHandleTop, &boxTop);
  384.     GetDialogItem(dlg, kSelectDirButtonBottom, &itemType, &itemHandleBottom, &boxBottom);
  385.     
  386.     if (item == sfHookFirstCall) {
  387.         pb.dirInfo.ioNamePtr = gDirBottom.name;
  388.         pb.dirInfo.ioVRefNum = -LMGetSFSaveDisk();
  389.         pb.dirInfo.ioFDirIndex = -1;
  390.         pb.dirInfo.ioDrDirID = LMGetCurDirStore();
  391.         PBGetCatInfo(&pb, false);
  392.         gDirBottom.vRefNum = pb.dirInfo.ioVRefNum;
  393.         gDirBottom.parID = pb.dirInfo.ioDrParID;
  394.         gDirTop = gDirBottom;
  395.     } else {
  396.         if (gReply->sfIsFolder || gReply->sfIsVolume || gReply->sfType == 'fdrp') {
  397.             gDirBottom = gReply->sfFile;
  398.             EnableBottomButton(dlg, true);
  399.         } else {
  400.             EnableBottomButton(dlg, false);
  401.             *gDirBottom.name = 0;
  402.         }
  403.         if (gReply->sfFile.parID == fsRtParID) {
  404.             FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder,
  405.                 &foundVRefNum, &foundDirID);
  406.             pb.dirInfo.ioNamePtr = gDirTop.name;
  407.             pb.dirInfo.ioVRefNum = foundVRefNum;
  408.             pb.dirInfo.ioFDirIndex = -1;
  409.             pb.dirInfo.ioDrDirID = foundDirID;
  410.             PBGetCatInfo(&pb, false);
  411.             gDirTop.vRefNum = pb.dirInfo.ioVRefNum;
  412.             gDirTop.parID = pb.dirInfo.ioDrParID;
  413.         } else {
  414.             pb.dirInfo.ioNamePtr = gDirTop.name;
  415.             pb.dirInfo.ioVRefNum = gReply->sfFile.vRefNum;
  416.             pb.dirInfo.ioFDirIndex = -1;
  417.             pb.dirInfo.ioDrDirID = gReply->sfFile.parID;
  418.             PBGetCatInfo(&pb, false);
  419.             gDirTop.vRefNum = pb.dirInfo.ioVRefNum;
  420.             gDirTop.parID = pb.dirInfo.ioDrParID;
  421.         }
  422.     }
  423.     
  424.     if (!EqualString(gPrevNameBottom, gDirBottom.name, false, true)) {
  425.         CopyPascalString(gPrevNameBottom, gDirBottom.name);
  426.         width = boxBottom.right - boxBottom.left - StringWidth(select) - 2*CharWidth(' ');
  427.         CopyPascalString(name, gDirBottom.name);
  428.         TruncString(width, name, smTruncMiddle);
  429.         p2cstr(name);
  430.         sprintf(buttonTitle, fmt, name);
  431.         c2pstr(buttonTitle);
  432.         SetControlTitle((ControlHandle)itemHandleBottom, (StringPtr)buttonTitle);
  433.         ValidRect(&boxBottom);
  434.     }
  435.     
  436.     if (!EqualString(gPrevNameTop, gDirTop.name, false, true)) {
  437.         CopyPascalString(gPrevNameTop, gDirTop.name);
  438.         width = boxTop.right - boxTop.left - StringWidth(select) - 2*CharWidth(' ');
  439.         CopyPascalString(name, gDirTop.name);
  440.         TruncString(width, name, smTruncMiddle);
  441.         p2cstr(name);
  442.         sprintf(buttonTitle, fmt, name);
  443.         c2pstr(buttonTitle);
  444.         SetControlTitle((ControlHandle)itemHandleTop, (StringPtr)buttonTitle);
  445.         ValidRect(&boxTop);
  446.     }
  447.     
  448.     /* Handle clicks on Select and Cancel buttons. */
  449.     
  450.     if (item == kSelectDirButtonTop) {
  451.         gSelect = 1;
  452.         return sfItemCancelButton;
  453.     } else if (item == kSelectDirButtonBottom) {
  454.         gSelect = 2;
  455.         return sfItemCancelButton;
  456.     } else if (item == sfItemCancelButton) {
  457.         gSelect = 0;
  458.         return sfItemCancelButton;
  459.     }
  460.     
  461.     return item;
  462. }
  463.  
  464.  
  465.  
  466. /*----------------------------------------------------------------------------
  467.     MyStandardGetDirectory 
  468.     
  469.     Present a custom standard get file dialog to select a directory.
  470.         
  471.     Exit:    reply->sfGood = true if directory selected, false if dialog canceled.    
  472.             reply->sfFile.vRefNum = vol ref num of selected directory.
  473.             reply->sfFile.parID = directory id of *parent* of selected directory.
  474.             reply->sfFile.name = name of selected directory.
  475.             *dirID = directory id of selected directory.
  476. ----------------------------------------------------------------------------*/
  477.  
  478. void MyStandardGetDirectory (StandardFileReply *reply, long *dirID)
  479. {
  480.     Point point = {-1,-1};
  481.     SFTypeList typeList = {'ƒldr', 0, 0, 0};
  482.     CInfoPBRec pb;
  483.     Boolean targetIsFolder, wasAliased;
  484.     
  485.     PrepUserInteraction();
  486.     SetMenusTo(kAppleAllEnabled, 0, 0, 0, 0, 0);
  487.  
  488.     *gPrevNameTop = *gPrevNameBottom = 0;
  489.     gReply = reply;
  490.     
  491.     CustomGetFile(gGetDirectoryFilterUPP, 1, typeList, reply, kDirSelectDlg, point,
  492.         gGetDirectoryHookUPP, gSFDialogFilterUPP, nil, nil, nil);
  493.         
  494.     reply->sfGood = gSelect != 0;
  495.     if (!reply->sfGood) return;
  496.     
  497.     if (gSelect == 1) {
  498.         reply->sfFile = gDirTop;
  499.     } else {
  500.         reply->sfFile = gDirBottom;
  501.     }
  502.     ResolveAliasFile(&reply->sfFile, true, &targetIsFolder, &wasAliased);
  503.  
  504.     pb.dirInfo.ioNamePtr = reply->sfFile.name;
  505.     pb.dirInfo.ioVRefNum = reply->sfFile.vRefNum;
  506.     pb.dirInfo.ioFDirIndex = 0;
  507.     pb.dirInfo.ioDrDirID = reply->sfFile.parID;
  508.     PBGetCatInfo(&pb, false);
  509.     *dirID = pb.dirInfo.ioDrDirID;       
  510. }
  511.  
  512.  
  513.  
  514. /*----------------------------------------------------------------------------
  515.     sfutil_InitUPP
  516.     
  517.     Initialize UPPs.
  518. ----------------------------------------------------------------------------*/
  519.  
  520. void sfutil_InitUPP (void)
  521. {
  522.      gGetDirectoryFilterUPP = NewFileFilterYDProc(GetDirectoryFilter);
  523.     gGetDirectoryHookUPP = NewDlgHookYDProc(GetDirectoryHook);
  524.     gSFDialogFilterUPP = NewModalFilterYDProc(SFDialogFilter);
  525.     gGetPutHookUPP = NewDlgHookYDProc(GetPutHook);
  526.     gMyStandardPutArticleHookUPP = NewDlgHookYDProc(MyStandardPutArticleHook);
  527.     gMyStandardAppendArticleHookUPP = NewDlgHookYDProc(MyStandardAppendArticleHook);
  528. }
  529.